﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;

namespace OrganizationName.DynamicData
{
    public class Schema : _ID
    {
        public string Name { get; set; }
        public int Type { get; set; }

        public Schema(string name)
        {
            Name = name;
        }

        public Schema CreateChild(string name)
        {
            Schema child = new Schema(name);
            child.Parent = this;
            Children.Add(child);
            return child;
        }

        public Schema CreateChild(string name, int type)
        {
            Schema child = CreateChild(name);
            child.Type = type;
            return child;
        }

        public Schema CreateChildNode(string name)
        {
            return CreateChild(name, 1);
        }

        public Schema CreateAttribute(string name)
        {
            return CreateChild(name, 2);
        }

        public Schema GetChild(string childName, int type)
        {
            if (Children != null)
            {
                foreach (Schema child in Children)
                {
                    if (child.Name == childName && child.Type == type)
                    {
                        return child;
                    }
                }
            }
            return null;
        }

        public Schema GetChildNode(string nodeName)
        {
            return GetChild(nodeName, 1);
        }

        public Schema GetAttribute(string attributeName)
        {
            return GetChild(attributeName, 2);
        }

        public static Schema FromXml(string name, string xmlPath)
        {
            System.Xml.XmlDocument xmlDocument = new System.Xml.XmlDocument();
            xmlDocument.Load(xmlPath);

            Schema schema = new Schema(name);

            FillSchema(schema, xmlDocument);

            return schema;
        }

        public static Schema FromDatabase(string name, string connectionString)
        {
            SqlConnection connection = new SqlConnection(connectionString);
            connection.Open();

            SqlCommand command = new SqlCommand
            (
                "DECLARE @SCHEMA_ID INT\r\n" +
                "Select @SCHEMA_ID = [ID] FROM [Schema] WHERE [Name] = @0 AND [Type] = 0\r\n" +
                "SELECT SCHEMA_ID = @SCHEMA_ID, * FROM [Schema] WHERE Root = @SCHEMA_ID OR [ID] = @SCHEMA_ID",
                connection
            );

            command.Parameters.AddWithValue("@0", name);

            SqlDataAdapter adapter = new SqlDataAdapter(command);

            DataTable schemaTable = new DataTable();
            adapter.Fill(schemaTable);

            connection.Close();
            connection.Dispose();
            command.Dispose();

            if (schemaTable.Rows.Count == 0)
            {
                return null;
            }

            Schema schema = new Schema(name);

            DataRow[] schemaRootRows = schemaTable.Select("ID = " + schemaTable.Rows[0]["SCHEMA_ID"]);

            FillSchema(schema, schemaRootRows[0]);

            return schema;
        }

        private static void FillSchema(Schema schema, System.Data.DataRow row)
        {
            schema.ID = Convert.ToInt32(row["ID"]);
            schema.Type = Convert.ToInt32(row["Type"]);

            DataRow[] childRows = row.Table.Select("[Parent] = " + row["ID"]);
            foreach (DataRow childRow in childRows)
            {
                Schema childSchema = schema.CreateChild(childRow["Name"].ToString());
                childSchema.Parent = schema;
                FillSchema(childSchema, childRow);
            }
        }

        private static void FillSchema(Schema schema, System.Xml.XmlNode node)
        {
            if (node.ChildNodes != null)
            {
                foreach (System.Xml.XmlNode childNode in node.ChildNodes)
                {
                    if (childNode is System.Xml.XmlElement)
                    {
                        Schema childSchema = schema.GetChildNode(childNode.Name);
                        if (childSchema == null)
                        {
                            childSchema = schema.CreateChildNode(childNode.Name);
                        }
                        FillSchema(childSchema, childNode);
                    }
                }
            }

            if (node.Attributes != null)
            {
                foreach (System.Xml.XmlAttribute childAttribute in node.Attributes)
                {
                    Schema childSchema = schema.GetAttribute(childAttribute.Name);
                    if (childSchema == null)
                    {
                        schema.CreateAttribute(childAttribute.Name);
                    }
                }
            }
        }

        public override string ToString()
        {
            return Name + " (" + (Type == 0 ? "Data" : Type == 1 ? "Node" : Type == 2 ? "Attribute" : Type.ToString()) + ")";
        }

        protected override string InsertScriptFieldList
        {
            get { return "[Name], [Type]"; }
        }

        protected override string InsertScriptValueList
        {
            get { return "'" + Name + "', " + Type; }
        }
    }
}
